#include "perspectivemanager.h"

#include "../mainwindow.h"

#include <QtGui/QAction>
#include <QtGui/QMenu>
#include <QtGui/QToolBar>

using namespace core;
using namespace swp;

PerspectiveManager::PerspectiveManager(MainWindow* parent) : QObject(parent),
    m_currentPerspective(0),
    m_perspectives(),
    m_actions(),
    m_actionsToPerspetive(),
    m_window(parent)
{

}

PerspectiveManager::~PerspectiveManager()
{

}

void PerspectiveManager::addPerspective(core::IPerspective* perspective)
{
    if (!m_perspectives.contains(perspective))
    {
        QAction* switchAction = new QAction(m_window);
        switchAction->setShortcut(
            QKeySequence(Qt::CTRL + (0x31 + m_perspectives.size())));
        switchAction->setShortcutContext(Qt::WindowShortcut);

        connect(switchAction, SIGNAL(triggered()), this,
            SLOT(perspectiveShortcut()));

        m_window->addAction(switchAction);

        m_actions.append(switchAction);

        m_perspectives.append(perspective);

        foreach (const QString& menuId, m_window->m_menus.keys())
        {
            const QList<QAction* > actions =
                perspective->getStaticActions(menuId);

            QMenu* menu = m_window->m_menus[menuId];

            foreach (QAction* action, actions)
            {
                menu->addAction(action);
            }
        }

        const QList<QToolBar* > toolbars =
            perspective->getStaticToolBars();

        foreach (QToolBar* toolbar, toolbars)
        {
            m_window->addToolBar(toolbar);
        }

        const QList<QAction* > ensuringActions =
            perspective->getPerspectiveEnsuringActions();

        foreach (QAction* action, ensuringActions)
        {
            if (!m_actionsToPerspetive.contains(action))
            {
                m_actionsToPerspetive[action] = perspective;

                connect(action, SIGNAL(triggered()),
                    this, SLOT(ensureOfPerspective()));
            }
        }
    }
}

void PerspectiveManager::removePerspective(
    core::IPerspective* perspective)
{
    if (m_perspectives.contains(perspective))
    {
        m_perspectives.removeAll(perspective);

        foreach (QAction* action, m_actions)
        {
            m_window->removeAction(action);

            delete action;
        }

        m_actions.clear();

        for (int i = 0; i < m_perspectives.size(); ++i)
        {
            QAction* switchAction = new QAction(m_window);
            switchAction->setShortcut(
                QKeySequence(Qt::CTRL + (0x31 + i)));
            switchAction->setShortcutContext(Qt::WindowShortcut);

            connect(switchAction, SIGNAL(triggered()), this,
                SLOT(perspectiveShortcut()));

            m_window->addAction(switchAction);

            m_actions.append(switchAction);
        }

        foreach (const QString& menuId, m_window->m_menus.keys())
        {
            const QList<QAction* > actions =
                perspective->getStaticActions(menuId);

            QMenu* menu = m_window->m_menus[menuId];

            foreach (QAction* action, actions)
            {
                menu->removeAction(action);
            }
        }

        const QList<QToolBar* > toolbars =
            perspective->getStaticToolBars();

        foreach (QToolBar* toolbar, toolbars)
        {
            m_window->removeToolBar(toolbar);
        }

        const QList<QAction* > ensuringActions =
            perspective->getPerspectiveEnsuringActions();

        foreach (QAction* action, ensuringActions)
        {
            if (!m_actionsToPerspetive.contains(action))
            {
                m_actionsToPerspetive.remove(action);

                disconnect(action, SIGNAL(triggered()),
                    this, SLOT(ensureOfPerspective()));
            }
        }
    }
}

void PerspectiveManager::setCurrent(IPerspective* current)
{
    if (m_perspectives.contains(current))
    {
        if (m_currentPerspective != 0)
        {
            foreach (const QString& menuId, m_window->m_menus.keys())
            {
                const QList<QAction*> actions =
                    m_currentPerspective->getContextActions(menuId);

                if (menuId != FINISHED)
                {
                    QMenu* menu = m_window->m_menus[menuId];

                    foreach (QAction* action, actions)
                    {
                        menu->removeAction(action);
                    }
                }
            }

            const QList<QToolBar* > toolBars =
                m_currentPerspective->getContextToolBars();

            foreach (QToolBar* toolBar, toolBars)
            {
                m_window->removeToolBar(toolBar);
            }

            m_currentPerspective->handleIsCurrentChanged(false);
        }

        m_currentPerspective = current;

        foreach (const QString& menuId, m_window->m_menus.keys())
        {
            const QList<QAction*> actions =
                m_currentPerspective->getContextActions(menuId);

            if (menuId != FINISHED)
            {
                QMenu* menu = m_window->m_menus[menuId];

                foreach (QAction* action, actions)
                {
                    menu->addAction(action);
                }
            }
        }

        const QList<QToolBar* > toolBars =
            m_currentPerspective->getContextToolBars();

        foreach (QToolBar* toolBar, toolBars)
        {
            m_window->addToolBar(toolBar);
            toolBar->show();
        }

        m_currentPerspective->handleIsCurrentChanged(true);
        emit perspectiveChanged(m_currentPerspective);
    }
}

const IPerspective* PerspectiveManager::getCurrent() const
{
    return m_currentPerspective;
}

const QList<IPerspective* > PerspectiveManager::perspectives() const
{
    return m_perspectives;
}

void PerspectiveManager::ensurePerspectiveRequest(IPerspective* perspective)
{
    const int index = m_perspectives.indexOf(perspective);

    if (index != -1)
    {
        emit ensurePerspectiveRequested(index);
    }
}

void PerspectiveManager::ensurePerspectiveRequest(int index)
{
    if (index >= 0 && index < m_perspectives.size())
    {
        emit ensurePerspectiveRequested(index);
    }
}

// slots
void PerspectiveManager::perspectiveChange(int index)
{
    if (index >= 0 && index < m_perspectives.size())
    {
        setCurrent(m_perspectives.at(index));
    }
}

// private slots
void PerspectiveManager::ensureOfPerspective()
{
    QAction* _sender = qobject_cast<QAction* >(sender());

    Q_ASSERT(_sender != 0); // shouldn't happen

    if (m_actionsToPerspetive.contains(_sender))
    {
        const int index = m_perspectives.indexOf(
            m_actionsToPerspetive[_sender]);

        if (index != -1)
        {
            emit ensurePerspectiveRequested(index);
        }
    }
}

void PerspectiveManager::perspectiveShortcut()
{
    int index = m_actions.indexOf(qobject_cast<QAction*>(sender()));
    if (index != -1)
    {
        ensurePerspectiveRequest(index);
    }
}
